home *** CD-ROM | disk | FTP | other *** search
/ EnigmA Amiga Run 1995 November / EnigmA AMIGA RUN 02 (1995)(G.R. Edizioni)(IT)[!][issue 1995-11][Skylink CD].iso / earcd / program / misc / bgui12.lha / Classes / PaletteClass / paletteclass.c next >
C/C++ Source or Header  |  1995-06-09  |  22KB  |  1,011 lines

  1. /*
  2. **           File: paletteclass.c
  3. **    Description: BOOPSI (BGUI) palette selector gadget class.
  4. **      Copyright: (C) Copyright 1995 Jaba Development.
  5. **             (C) Copyright 1995 Jan van den Baard.
  6. **             All Rights Reserved.
  7. **/
  8.  
  9. #include <exec/types.h>
  10. #include <intuition/intuition.h>
  11. #include <graphics/gfxmacros.h>
  12. #include <libraries/bgui.h>
  13.  
  14. #include <clib/alib_protos.h>
  15.  
  16. #include <proto/exec.h>
  17. #include <proto/intuition.h>
  18. #include <proto/graphics.h>
  19. #include <proto/bgui.h>
  20. #include <proto/utility.h>
  21.  
  22. #include <string.h>
  23.  
  24. #include "paletteclass.h"
  25.  
  26. /*
  27. **    Compiler stuff.
  28. **/
  29. #ifdef _DCC
  30. #define SAVEDS __geta4
  31. #define ASM
  32. #define REG(x) __ ## x
  33. #else
  34. #define SAVEDS __saveds
  35. #define ASM __asm
  36. #define REG(x) register __ ## x
  37. #endif
  38.  
  39. /*
  40. **    Clamp a value in a range.
  41. **/
  42. #define CLAMP(v,i,a)    if ( v < i ) v = i; else if ( v > a ) v = a;
  43.  
  44. /*
  45. **    Simple type-cast.
  46. **/
  47. #define GAD(x)        (( struct Gadget * )x)
  48.  
  49. /*
  50. **    PaletteClass object instance data.
  51. **/
  52. typedef struct {
  53.     UWORD        pd_ColorOffset;         /* Offset in palette/table.         */
  54.     UWORD        pd_Depth;        /* Palette depth.             */
  55.     UWORD        pd_NumColors;        /* Number of colors.             */
  56.     UWORD           *pd_PenTable;        /* Table of pens.             */
  57.     UWORD        pd_CurrentColor;    /* Currently selected color.         */
  58.     Object           *pd_Frame;        /* Frame for selected color.         */
  59.     UWORD        pd_Columns;        /* Number of columns.             */
  60.     struct IBox    pd_ColorBox;        /* Bounds of real color box.         */
  61.     UWORD        pd_RectWidth;        /* Width of color rectangle.         */
  62.     UWORD        pd_RectHeight;        /* Height of color rectangle.         */
  63.     UWORD        pd_InitialColor;    /* Color selected when going active. */
  64.     BOOL        pd_ResetInitial;    /* Reset initial color?              */
  65. } PD;
  66.  
  67. /*
  68. **    Make sure that "CurrentColor" is a valid
  69. **    pen number in the colors which are displayed
  70. **    in the palette object.
  71. **/
  72. STATIC ASM UWORD ValidateColor( REG(a0) PD *pd, REG(d0) ULONG pen )
  73. {
  74.     UWORD            *tab = pd->pd_PenTable, i;
  75.  
  76.     /*
  77.     **    Do we have a pen table?
  78.     **/
  79.     if ( tab ) {
  80.         /*
  81.         **    Check the pens in the table.
  82.         **/
  83.         for ( i = 0; i < pd->pd_NumColors; i++ ) {
  84.             /*
  85.             **    Does the pen exist in the
  86.             **    pen table?
  87.             **/
  88.             if ( pen == tab[ i + pd->pd_ColorOffset ] )
  89.                 return( pen );
  90.         }
  91.         /*
  92.         **    The pen does not exist in the table.
  93.         **    Make it the first pen in the table.
  94.         **/
  95.         i = tab[ pd->pd_ColorOffset ];
  96.     } else {
  97.         /*
  98.         **    Check if the pen number is
  99.         **    in range.
  100.         **/
  101.         if ( pen >= pd->pd_ColorOffset && pen <= ( pd->pd_ColorOffset + pd->pd_NumColors - 1 ))
  102.             return( pen );
  103.         /*
  104.         **    No. Default to the first pen.
  105.         **/
  106.         i = pd->pd_ColorOffset;
  107.     }
  108.  
  109.     return( i );
  110. }
  111.  
  112. /*
  113. **    Create a new palette object.
  114. **/
  115. STATIC ASM ULONG PaletteClassNew( REG(a0) Class *cl, REG(a2) Object *obj, REG(a1) struct opSet *ops )
  116. {
  117.     PD            *pd;
  118.     struct TagItem        *tstate = ops->ops_AttrList, *tag;
  119.     Object            *label;
  120.     ULONG             rc, place;
  121.  
  122.     /*
  123.     **    Let the superclass make the object.
  124.     **/
  125.     if ( rc = DoSuperMethodA( cl, obj, ( Msg )ops )) {
  126.         /*
  127.         **    Get a pointer to the object
  128.         **    it's instance data.
  129.         **/
  130.         pd = ( PD * )INST_DATA( cl, rc );
  131.  
  132.         /*
  133.         **    Preset the data to 0. Don't
  134.         **    know if this is necessary.
  135.         **/
  136.         bzero(( char * )pd, sizeof( PD ));
  137.  
  138.         /*
  139.         **    Setup the default settings.
  140.         **/
  141.         pd->pd_Depth        = 1;
  142.         pd->pd_NumColors    = 2;
  143.  
  144.         /*
  145.         **    Setup the instance data.
  146.         **/
  147.         while ( tag = NextTagItem( &tstate )) {
  148.             switch ( tag->ti_Tag ) {
  149.  
  150.                 case    PALETTE_Depth:
  151.                     pd->pd_Depth     = tag->ti_Data;
  152.                     CLAMP( pd->pd_Depth, 1, 8 );
  153.                     pd->pd_NumColors = ( 1L << pd->pd_Depth );
  154.                     break;
  155.  
  156.                 case    PALETTE_ColorOffset:
  157.                     pd->pd_ColorOffset = tag->ti_Data;
  158.                     break;
  159.  
  160.                 case    PALETTE_PenTable:
  161.                     pd->pd_PenTable = ( UWORD * )tag->ti_Data;
  162.                     break;
  163.  
  164.                 case    PALETTE_CurrentColor:
  165.                     pd->pd_CurrentColor = tag->ti_Data;
  166.                     break;
  167.             }
  168.         }
  169.  
  170.         /*
  171.         **    Make sure the offset stays in range.
  172.         **/
  173.         CLAMP( pd->pd_ColorOffset,  0, 256 - pd->pd_NumColors );
  174.  
  175.         /*
  176.         **    The color must remain OK.
  177.         **/
  178.         pd->pd_CurrentColor = ValidateColor( pd, pd->pd_CurrentColor );
  179.  
  180.         /*
  181.         **    See if the object has a label
  182.         **    attached to it.
  183.         **/
  184.         DoMethod(( Object * )rc, OM_GET, BT_LabelObject, &label );
  185.         if ( label ) {
  186.             /*
  187.             **    Yes. Query the place because it may
  188.             **    not be PLACE_IN for obvious reasons.
  189.             **/
  190.             DoMethod( label, OM_GET, LAB_Place, &place );
  191.             if ( place == PLACE_IN )
  192.                 SetAttrs( label, LAB_Place, PLACE_LEFT, TAG_END );
  193.         }
  194.  
  195.         /*
  196.         **    Create a frame for the
  197.         **    currently selected pen.
  198.         **/
  199.         if ( pd->pd_Frame = BGUI_NewObject( BGUI_FRAME_IMAGE, FRM_Type, FRTYPE_BUTTON, FRM_Flags, FRF_RECESSED, TAG_END ))
  200.             return( rc );
  201.  
  202.         /*
  203.         **    No frame means no object.
  204.         **/
  205.         CoerceMethod( cl, ( Object * )rc, OM_DISPOSE );
  206.     }
  207.     return( 0L);
  208. }
  209.  
  210. /*
  211. **    Dispose of the object.
  212. **/
  213. STATIC ASM ULONG PaletteClassDispose( REG(a0) Class *cl, REG(a2) Object *obj, REG(a1) Msg msg )
  214. {
  215.     PD            *pd = ( PD * )INST_DATA( cl, obj );
  216.  
  217.     /*
  218.     **    Dispose of the frame.
  219.     **/
  220.     if ( pd->pd_Frame )    DoMethod( pd->pd_Frame, OM_DISPOSE );
  221.  
  222.     /*
  223.     **    The superclass handles
  224.     **    the rest.
  225.     **/
  226.     return( DoSuperMethodA( cl, obj, msg ));
  227. }
  228.  
  229. /*
  230. **    Get an attribute.
  231. **/
  232. STATIC ASM ULONG PaletteClassGet( REG(a0) Class *cl, REG(a2) Object *obj, REG(a1) struct opGet *opg )
  233. {
  234.     PD            *pd = ( PD * )INST_DATA( cl, obj );
  235.     ULONG             rc = 1L;
  236.  
  237.     /*
  238.     **    We only know one attribute.
  239.     **/
  240.     if ( opg->opg_AttrID == PALETTE_CurrentColor )
  241.         /*
  242.         **    Pass on the currently
  243.         **    selected color.
  244.         **/
  245.         *( opg->opg_Storage ) = pd->pd_CurrentColor;
  246.     else
  247.         /*
  248.         **    Everything else goes
  249.         **    to the superclass.
  250.         **/
  251.         rc = DoSuperMethodA( cl, obj, ( Msg )opg );
  252.  
  253.     return( rc );
  254. }
  255.  
  256. /*
  257. **    Render the color rectangles
  258. **    inside the palette object it's
  259. **    color box.
  260. **/
  261. STATIC ASM VOID RenderColorRects( REG(a0) PD *pd, REG(a1) struct RastPort *rp, REG(a2) struct IBox *area, REG(a3) struct DrawInfo *dri )
  262. {
  263.     UWORD        colorwidth, colorheight, columns = 1, rows = 1, depth = pd->pd_Depth;
  264.     UWORD        hadjust = 0, vadjust = 0, left, top, colsize, rowsize, c, r, color;
  265.     UWORD        offset = pd->pd_ColorOffset;
  266.  
  267.     /*
  268.     **    Get the first color of the
  269.     **    displayed palette.
  270.     **/
  271.     if ( pd->pd_PenTable ) color = pd->pd_PenTable[ offset ];
  272.     else               color = offset;
  273.  
  274.     /*
  275.     **    Get the Width and height of the
  276.     **    area in which we layout the
  277.     **    color rectangles.
  278.     **/
  279.     colorwidth  = area->Width;
  280.     colorheight = area->Height;
  281.  
  282.     /*
  283.     **    Layout the color
  284.     **    rectangles.
  285.     **/
  286.     while ( depth ) {
  287.         if (( colorheight << 1 ) > colorwidth ) {
  288.             colorheight >>= 1;
  289.             rows        <<= 1;
  290.         } else {
  291.             colorwidth  >>= 1;
  292.             columns     <<= 1;
  293.         }
  294.         depth--;
  295.     }
  296.  
  297.     /*
  298.     **    Compute the pixel width and
  299.     **    height of the color rectangles.
  300.     **/
  301.     colsize = area->Width  / columns;
  302.     rowsize = area->Height / rows;
  303.  
  304.     /*
  305.     **    Since this is not precise
  306.     **    we compute the space left
  307.     **    over to adjust the left
  308.     **    and top offset at which we
  309.     **    begin.
  310.     **
  311.     **    Also we re-compute the color
  312.     **    box dimensions.
  313.     **/
  314.     hadjust = ( area->Width  - ( area->Width  = colsize * columns )) >> 1;
  315.     vadjust = ( area->Height - ( area->Height = rowsize * rows    )) >> 1;
  316.  
  317.     /*
  318.     **    Adjust the colorbox position.
  319.     **/
  320.     area->Left += hadjust;
  321.     area->Top  += vadjust;
  322.  
  323.     /*
  324.     **    Get initial left and top offset.
  325.     **/
  326.     left = area->Left + 1;
  327.     top  = area->Top  + 1;
  328.  
  329.     /*
  330.     **    No patterns!
  331.     **/
  332.     SetAfPt( rp, NULL, 0 );
  333.  
  334.     /*
  335.     **    Set these up. We need this information to
  336.     **    compute the color the mouse is over.
  337.     **/
  338.     pd->pd_Columns      = columns;
  339.     pd->pd_RectWidth  = colsize;
  340.     pd->pd_RectHeight = rowsize;
  341.  
  342.     /*
  343.     **    Now render the rectangles.
  344.     **/
  345.     for ( r = 0; r < rows; r++ ) {
  346.         for ( c = 0; c < columns; c++ ) {
  347.             /*
  348.             **    The currently selected color
  349.             **    is done with a frameclass object.
  350.             **/
  351.             if ( color == pd->pd_CurrentColor ) {
  352.                 /*
  353.                 **    Setup the object.
  354.                 **/
  355.                 SetAttrs( pd->pd_Frame, IA_Left,    left,
  356.                             IA_Top,         top,
  357.                             IA_Width,    colsize - 1,
  358.                             IA_Height,    rowsize - 1,
  359.                             FRM_BackPen,    color,
  360.                             TAG_END );
  361.                 /*
  362.                 **    Render it.
  363.                 **/
  364.                 DrawImageState( rp, ( struct Image * )pd->pd_Frame, 0, 0, IDS_NORMAL, dri );
  365.             } else {
  366.                 /*
  367.                 **    Other colors we do ourselves.
  368.                 **/
  369.                 SetAPen( rp, color );
  370.                 RectFill( rp, left, top, left + colsize - 2, top + rowsize - 2 );
  371.             }
  372.             left += colsize;
  373.             /*
  374.             **    Get the next color from the
  375.             **    displayed palette.
  376.             **/
  377.             if ( pd->pd_PenTable ) color = pd->pd_PenTable[ ++offset ];
  378.             else               color++;
  379.         }
  380.         left = area->Left + 1;
  381.         top += rowsize;
  382.     }
  383. }
  384.  
  385. /*
  386. **    Render the palette object.
  387. **/
  388. STATIC ASM ULONG PaletteClassRender( REG(a0) Class *cl, REG(a2) Object *obj, REG(a1) struct gpRender *gpr )
  389. {
  390.     PD            *pd = ( PD * )INST_DATA( cl, obj );
  391.     struct RastPort          rp = *gpr->gpr_RPort;
  392.     struct DrawInfo         *dri = gpr->gpr_GInfo->gi_DrInfo;
  393.     struct IBox        *bounds;
  394.     Object            *frame;
  395.     ULONG             fw = 0, fh = 0;
  396.     static UWORD         dispat[ 2 ] = { 0x2222, 0x8888 };
  397.     ULONG             rc;
  398.  
  399.     /*
  400.     **    First we let the superclass
  401.     **    render. If it returns 0 we
  402.     **    do not render!
  403.     **/
  404.     if ( rc = DoSuperMethodA( cl, obj, ( Msg )gpr )) {
  405.         /*
  406.         **    Get the hitbox bounds of the object
  407.         **    and copy it's contents. We need to
  408.         **    copy the data because we must adjust
  409.         **    it's contents.
  410.         **/
  411.         DoMethod( obj, OM_GET, BT_HitBox, &bounds );
  412.         pd->pd_ColorBox = *bounds;
  413.  
  414.         /*
  415.         **    Do we have a frame?
  416.         **/
  417.         DoMethod( obj, OM_GET, BT_FrameObject, &frame );
  418.         if ( frame ) {
  419.             /*
  420.             **    Find out the frame thickness.
  421.             **/
  422.             DoMethod( frame, OM_GET, FRM_FrameWidth,  &fw );
  423.             DoMethod( frame, OM_GET, FRM_FrameHeight, &fh );
  424.             fw++;
  425.             fh++;
  426.  
  427.             /*
  428.             **    Adjust bounds accoordingly.
  429.             **/
  430.             pd->pd_ColorBox.Left      += fw;
  431.             pd->pd_ColorBox.Top      += fh;
  432.             pd->pd_ColorBox.Width      -= fw << 1;
  433.             pd->pd_ColorBox.Height      -= fh << 1;
  434.         }
  435.  
  436.         /*
  437.         **    Render the color rectangles.
  438.         **/
  439.         RenderColorRects( pd, &rp, &pd->pd_ColorBox, dri );
  440.  
  441.         /*
  442.         **    Disabled?
  443.         **/
  444.         if ( GAD( obj )->Flags & GFLG_DISABLED ) {
  445.             SetAPen( &rp, dri ? dri->dri_Pens[ SHADOWPEN ] : 2 );
  446.             SetDrMd( &rp, JAM1 );
  447.             SetAfPt( &rp, dispat, 1 );
  448.             RectFill( &rp, bounds->Left,
  449.                        bounds->Top,
  450.                        bounds->Left + bounds->Width  - 1,
  451.                        bounds->Top  + bounds->Height - 1 );
  452.         }
  453.  
  454.     }
  455.     return( rc );
  456. }
  457.  
  458. /*
  459. **    Get the pen number of
  460. **    ordinal color number "num".
  461. **/
  462. STATIC ASM ULONG GetPenNumber( REG(a0) PD *pd, REG(d0) ULONG num )
  463. {
  464.     /*
  465.     **    Return the pen number
  466.     **    from the pen table or...
  467.     **/
  468.     if ( pd->pd_PenTable ) return( pd->pd_PenTable[ pd->pd_ColorOffset + num ] );
  469.  
  470.     /*
  471.     **    From the screen palette.
  472.     **/
  473.     return( num + pd->pd_ColorOffset );
  474. }
  475.  
  476. /*
  477. **    Determine the ordinal number
  478. **    of the pen in the object.
  479. **/
  480. STATIC ASM ULONG GetOrdinalNumber( REG(a0) PD *pd, REG(d0) ULONG pen )
  481. {
  482.     UWORD            *tab = pd->pd_PenTable, i;
  483.  
  484.     /*
  485.     **    Do we have a pen table?
  486.     **/
  487.     if ( tab ) {
  488.         /*
  489.         **    Look up the pen in the table.
  490.         **/
  491.         for ( i = 0; i < pd->pd_NumColors; i++ ) {
  492.             /*
  493.             **    Is this the one?
  494.             **/
  495.             if ( tab[ i + pd->pd_ColorOffset ] == pen )
  496.                 return( i );
  497.         }
  498.     }
  499.  
  500.     /*
  501.     **    Return the ordinal palette pen.
  502.     **/
  503.     return( pen - pd->pd_ColorOffset );
  504. }
  505.  
  506. /*
  507. **    Determine which color rectangle
  508. **    the coordinates are in.
  509. **/
  510. STATIC ASM UWORD GetColor( REG(a0) PD *pd, REG(d0) ULONG x, REG(d1) ULONG y )
  511. {
  512.     UWORD        col, row;
  513.  
  514.     /*
  515.     **    Compute the row and column
  516.     **    we clicked on.
  517.     **/
  518.     row = y / pd->pd_RectHeight;
  519.     col = x / pd->pd_RectWidth;
  520.  
  521.     /*
  522.     **    With this information we can simple
  523.     **    compute and return the color under
  524.     **    these coordinates.
  525.     **/
  526.     return( GetPenNumber( pd, ( row * pd->pd_Columns ) + col ));
  527. }
  528.  
  529. /*
  530. **    Get the top-left position of
  531. **    a color in the color box.
  532. **/
  533. STATIC ASM GetTopLeft( REG(a0) PD *pd, REG(d0) UWORD color, REG(a1) UWORD *x, REG(a2) UWORD *y )
  534. {
  535.     UWORD            row, col;
  536.  
  537.     /*
  538.     **    First compute the row and column
  539.     **    of the color.
  540.     **/
  541.     row = color / pd->pd_Columns;
  542.     col = color - ( row * pd->pd_Columns );
  543.  
  544.     /*
  545.     **    Now we can simply get the
  546.     **    x/y position of the color
  547.     **    box.
  548.     **/
  549.     *x = pd->pd_ColorBox.Left + ( col * pd->pd_RectWidth  );
  550.     *y = pd->pd_ColorBox.Top  + ( row * pd->pd_RectHeight );
  551. }
  552.  
  553. /*
  554. **    Notify about an attribute change.
  555. **/
  556. STATIC ULONG NotifyAttrChange( Object *obj, struct GadgetInfo *gi, ULONG flags, Tag tag1, ... )
  557. {
  558.     return( DoMethod( obj, OM_NOTIFY, &tag1, gi, flags ));
  559. }
  560.  
  561. /*
  562. **    Change the currently selected color.
  563. **/
  564. STATIC ASM VOID ChangeSelectedColor( REG(a0) PD *pd, REG(a1) struct GadgetInfo *gi, REG(d0) ULONG newcolor )
  565. {
  566.     struct RastPort         *rp;
  567.     UWORD             l, t;
  568.  
  569.     /*
  570.     **    Allocate a rastport.
  571.     **/
  572.     if ( gi && ( rp = ObtainGIRPort( gi ))) {
  573.         /*
  574.         **    First pickup the coordinates
  575.         **    of the currently selected
  576.         **    color.
  577.         **/
  578.         GetTopLeft( pd, GetOrdinalNumber( pd, pd->pd_CurrentColor ), &l, &t );
  579.  
  580.         /*
  581.         **    Render this color rectangle
  582.         **    as not-selected.
  583.         **/
  584.         SetAPen( rp, pd->pd_CurrentColor );
  585.         RectFill( rp, l + 1,
  586.                   t + 1,
  587.                   l + pd->pd_RectWidth  - 1,
  588.                   t + pd->pd_RectHeight - 1 );
  589.  
  590.         /*
  591.         **    Now pickup the coordinates
  592.         **    of the new selected color.
  593.         **/
  594.         GetTopLeft( pd, GetOrdinalNumber( pd, newcolor ), &l, &t );
  595.  
  596.         /*
  597.         **    Setup and render the frame to
  598.         **    reflect the new data.
  599.         **/
  600.         SetAttrs( pd->pd_Frame, IA_Left,     l + 1,
  601.                     IA_Top,      t + 1,
  602.                     IA_Width,    pd->pd_RectWidth  - 1,
  603.                     IA_Height,   pd->pd_RectHeight - 1,
  604.                     FRM_BackPen, newcolor,
  605.                     TAG_END );
  606.  
  607.         DrawImageState( rp, ( struct Image * )pd->pd_Frame, 0, 0, IDS_NORMAL, gi->gi_DrInfo );
  608.  
  609.         /*
  610.         **    Free up the rastport.
  611.         **/
  612.         ReleaseGIRPort( rp );
  613.     }
  614.     /*
  615.     **    Setup the new color.
  616.     **/
  617.     pd->pd_CurrentColor = newcolor;
  618. }
  619.  
  620. /*
  621. **    Set attributes.
  622. **/
  623. STATIC ASM ULONG PaletteClassSet( REG(a0) Class *cl, REG(a2) Object *obj, REG(a1) struct opUpdate *opu )
  624. {
  625.     PD            *pd = ( PD * )INST_DATA( cl, obj );
  626.     struct TagItem        *tag;
  627.     ULONG             rc, new;
  628.  
  629.     /*
  630.     **    First the superclass.
  631.     **/
  632.     rc = DoSuperMethodA( cl, obj, ( Msg )opu );
  633.  
  634.     /*
  635.     **    Frame thickness change? When the window in which
  636.     **    we are located has WINDOW_AutoAspect set to TRUE
  637.     **    the windowclass distributes the FRM_ThinFrame
  638.     **    attribute to the objects in the window. Here we
  639.     **    simply intercept it to set the selected color
  640.     **    frame thickness.
  641.     **/
  642.     if ( tag = FindTagItem( FRM_ThinFrame, opu->opu_AttrList ))
  643.         /*
  644.         **    Set it to the frame.
  645.         **/
  646.         SetAttrs( pd->pd_Frame, FRM_ThinFrame, tag->ti_Data, TAG_END );
  647.  
  648.     /*
  649.     **    Color change?
  650.     **/
  651.     if ( tag = FindTagItem( PALETTE_CurrentColor, opu->opu_AttrList )) {
  652.         /*
  653.         **    Make sure it's valid.
  654.         **/
  655.         new = ValidateColor( pd, tag->ti_Data );
  656.         /*
  657.         **    Did it really change?
  658.         **/
  659.         if ( new != pd->pd_CurrentColor ) {
  660.             /*
  661.             **    Yes. Show it and notify
  662.             **    the change.
  663.             **/
  664.             ChangeSelectedColor( pd, opu->opu_GInfo, new );
  665.             NotifyAttrChange( obj, opu->opu_GInfo, opu->MethodID == OM_UPDATE ? opu->opu_Flags : 0L, GA_ID, GAD( obj )->GadgetID, PALETTE_CurrentColor, pd->pd_CurrentColor, TAG_END );
  666.         }
  667.     }
  668.     return( rc );
  669. }
  670.  
  671. /*
  672. **    Let's go active :)
  673. **/
  674. STATIC ASM ULONG PaletteClassGoActive( REG(a0) Class *cl, REG(a2) Object *obj, REG(a1) struct gpInput *gpi )
  675. {
  676.     PD            *pd = ( PD * )INST_DATA( cl, obj );
  677.     WORD             l, t;
  678.     UWORD             newcol;
  679.     ULONG             rc = GMR_NOREUSE;
  680.  
  681.     /*
  682.     **    We do not go active when we are
  683.     **    disabled or when we where activated
  684.     **    by the ActivateGadget() call.
  685.     **/
  686.     if (( GAD( obj )->Flags & GFLG_DISABLED ) || ( ! gpi->gpi_IEvent ))
  687.         return( rc );
  688.  
  689.     /*
  690.     **    Save color selected when going
  691.     **    active. This way we can reset
  692.     **    the initial color when the
  693.     **    gadget activity is aborted by
  694.     **    the user or intuition.
  695.     **/
  696.     pd->pd_InitialColor = pd->pd_CurrentColor;
  697.  
  698.     /*
  699.     **    Get the coordinates relative
  700.     **    to the top-left of the colorbox.
  701.     **/
  702.     l = gpi->gpi_Mouse.X - ( pd->pd_ColorBox.Left - GAD( obj )->LeftEdge );
  703.     t = gpi->gpi_Mouse.Y - ( pd->pd_ColorBox.Top  - GAD( obj )->TopEdge  );
  704.  
  705.     /*
  706.     **    Are we really hit?
  707.     **/
  708.     if ( l >= 0 && t >= 0 && l < pd->pd_ColorBox.Width && t < pd->pd_ColorBox.Height ) {
  709.         /*
  710.         **    Did the color change?
  711.         **/
  712.         if (( newcol = GetColor( pd, l, t )) != pd->pd_CurrentColor ) {
  713.             /*
  714.             **    Yes. Setup the new color and send
  715.             **    a notification.
  716.             **/
  717.             ChangeSelectedColor( pd, gpi->gpi_GInfo, newcol );
  718.             NotifyAttrChange( obj, gpi->gpi_GInfo, 0L, GA_ID, GAD( obj )->GadgetID, PALETTE_CurrentColor, pd->pd_CurrentColor, TAG_END );
  719.         }
  720.         /*
  721.         **    Go active.
  722.         **/
  723.         rc = GMR_MEACTIVE;
  724.     }
  725.     return( rc );
  726. }
  727.  
  728. /*
  729. **    Handle the user input.
  730. **/
  731. STATIC ASM ULONG PaletteClassHandleInput( REG(a0) Class *cl, REG(a2) Object *obj, REG(a1) struct gpInput *gpi )
  732. {
  733.     PD            *pd = ( PD * )INST_DATA( cl, obj );
  734.     WORD             l, t;
  735.     UWORD             newcol;
  736.     ULONG             rc = GMR_MEACTIVE;
  737.  
  738.     /*
  739.     **    Get the coordinates relative
  740.     **    to the top-left of the colorbox.
  741.     **/
  742.     l = gpi->gpi_Mouse.X - ( pd->pd_ColorBox.Left - GAD( obj )->LeftEdge );
  743.     t = gpi->gpi_Mouse.Y - ( pd->pd_ColorBox.Top  - GAD( obj )->TopEdge  );
  744.  
  745.     /*
  746.     **    Mouse pointer located over the object?
  747.     **/
  748.     if ( l >= 0 && t >= 0 && l < pd->pd_ColorBox.Width && t < pd->pd_ColorBox.Height ) {
  749.         /*
  750.         **    Mouse over a new color?
  751.         **/
  752.         if (( newcol = GetColor( pd, l, t )) != pd->pd_CurrentColor ) {
  753.             /*
  754.             **    Change the selected color.
  755.             **/
  756.             ChangeSelectedColor( pd, gpi->gpi_GInfo, newcol );
  757.             /*
  758.             **    Send notification
  759.             **    about the change.
  760.             **/
  761.             NotifyAttrChange( obj, gpi->gpi_GInfo, 0L, GA_ID, GAD( obj )->GadgetID, PALETTE_CurrentColor, pd->pd_CurrentColor, TAG_END );
  762.         }
  763.     }
  764.  
  765.     /*
  766.     **    Check mouse input.
  767.     **/
  768.     if ( gpi->gpi_IEvent->ie_Class == IECLASS_RAWMOUSE ) {
  769.         switch ( gpi->gpi_IEvent->ie_Code ) {
  770.  
  771.             case    SELECTUP:
  772.                 /*
  773.                 **    Left-mouse button up means we
  774.                 **    return GMR_VERIFY.
  775.                 **/
  776.                 rc = GMR_NOREUSE | GMR_VERIFY;
  777.                 break;
  778.  
  779.             case    MENUDOWN:
  780.                 /*
  781.                 **    The menu button aborts the
  782.                 **    selection.
  783.                 **/
  784.                 pd->pd_ResetInitial = TRUE;
  785.                 rc = GMR_NOREUSE;
  786.                 break;
  787.         }
  788.     }
  789.     return( rc );
  790. }
  791.  
  792. /*
  793. **    Go inactive.
  794. **/
  795. STATIC ASM ULONG PaletteClassGoInactive( REG(a0) Class *cl, REG(a2) Object *obj, REG(a1) struct gpGoInactive *ggi )
  796. {
  797.     PD            *pd = ( PD * )INST_DATA( cl, obj );
  798.  
  799.     /*
  800.     **    Reset initial color?
  801.     **/
  802.     if ( pd->pd_ResetInitial || ggi->gpgi_Abort == 1 ) {
  803.         /*
  804.         **    Reset color.
  805.         **/
  806.         ChangeSelectedColor( pd, ggi->gpgi_GInfo, pd->pd_InitialColor );
  807.         /*
  808.         **    Notification of the reset.
  809.         **/
  810.         NotifyAttrChange( obj, ggi->gpgi_GInfo, 0L, GA_ID, GAD( obj )->GadgetID, PALETTE_CurrentColor, pd->pd_CurrentColor, TAG_END );
  811.         /*
  812.         **    Clear reset flag.
  813.         **/
  814.         pd->pd_ResetInitial = FALSE;
  815.     }
  816.  
  817.     return( DoSuperMethodA( cl, obj, ( Msg )ggi ));
  818. }
  819.  
  820. /*
  821. **    Tell'm our minimum dimensions.
  822. **/
  823. STATIC ASM ULONG PaletteClassDimensions( REG(a0) Class *cl, REG(a2) Object *obj, REG(a1) struct grmDimensions *dim )
  824. {
  825.     PD            *pd = ( PD * )INST_DATA( cl, obj );
  826.     UWORD             mx, my;
  827.     ULONG             rc;
  828.  
  829.     /*
  830.     **    First the superclass.
  831.     **/
  832.     rc = DoSuperMethodA( cl, obj, ( Msg )dim );
  833.  
  834.     /*
  835.     **    Now we pass our requirements. Note that
  836.     **    it is a bit difficult for this type of
  837.     **    gadgetclass to determine a suitable
  838.     **    minimum size. It would probably be
  839.     **    best to add tags for optional
  840.     **    specification. I'll leave it at this
  841.     **    for now.
  842.     **/
  843.     switch ( pd->pd_NumColors ) {
  844.  
  845.         case    2:
  846.         case    4:
  847.         case    8:
  848.             mx = 16;
  849.             my = 16;
  850.             break;
  851.  
  852.         case    16:
  853.         case    32:
  854.             mx = 32;
  855.             my = 32;
  856.             break;
  857.  
  858.         default:
  859.             mx = 64;
  860.             my = 64;
  861.             break;
  862.     }
  863.  
  864.     /*
  865.     **    Store these values.
  866.     **/
  867.     *( dim->grmd_MinSize.Width  ) += mx;
  868.     *( dim->grmd_MinSize.Height ) += my;
  869.  
  870.     return( rc );
  871. }
  872.  
  873. /*
  874. **    Key activation.
  875. **/
  876. STATIC ASM PaletteClassKeyActive( REG(a0) Class *cl, REG(a2) Object *obj, REG(a1) struct wmKeyInput *wmki )
  877. {
  878.     PD            *pd = ( PD * )INST_DATA( cl, obj );
  879.     UWORD             qual = wmki->wmki_IEvent->ie_Qualifier, new;
  880.  
  881.     /*
  882.     **    Get the ordinal number of
  883.     **    the currently selected pen.
  884.     **/
  885.     new = GetOrdinalNumber( pd, pd->pd_CurrentColor );
  886.  
  887.     /*
  888.     **    Shifted is backwards, normal forward.
  889.     **/
  890.     if ( qual & ( IEQUALIFIER_LSHIFT | IEQUALIFIER_RSHIFT )) {
  891.         if ( new               ) new--;
  892.         else                     new = pd->pd_NumColors - 1;
  893.     } else {
  894.         if ( new < ( pd->pd_NumColors - 1 )) new++;
  895.         else                     new = 0;
  896.     }
  897.  
  898.     /*
  899.     **    Change the color.
  900.     **/
  901.     ChangeSelectedColor( pd, wmki->wmki_GInfo, GetPenNumber( pd, new ));
  902.  
  903.     /*
  904.     **    Notify the change.
  905.     **/
  906.     NotifyAttrChange( obj, wmki->wmki_GInfo, 0L, GA_ID, GAD( obj )->GadgetID, PALETTE_CurrentColor, pd->pd_CurrentColor, TAG_END );
  907.  
  908.     /*
  909.     **    Setup ID to report to
  910.     **    the event handler.
  911.     **/
  912.     *( wmki->wmki_ID ) = GAD( obj )->GadgetID;
  913.  
  914.     return( WMKF_VERIFY );
  915. }
  916.  
  917. /*
  918. **    The class dispatcher. Here's
  919. **    where the fun starts.
  920. **
  921. **    SAS Users: You should either compile this module with
  922. **           stack checking turned off (NOSTACKCHECK) or
  923. **           you must use the "__interrupt" qualifier in
  924. **           this routine.
  925. **/
  926. STATIC SAVEDS ASM ULONG PaletteClassDispatch( REG(a0) Class *cl, REG(a2) Object *obj, REG(a1) Msg msg )
  927. {
  928.     ULONG            rc;
  929.  
  930.     switch ( msg->MethodID ) {
  931.  
  932.         case    OM_NEW:
  933.             rc = PaletteClassNew( cl, obj, ( struct opSet * )msg );
  934.             break;
  935.  
  936.         case    OM_DISPOSE:
  937.             rc = PaletteClassDispose( cl, obj, msg );
  938.             break;
  939.  
  940.         case    OM_GET:
  941.             rc = PaletteClassGet( cl, obj, ( struct opGet * )msg );
  942.             break;
  943.  
  944.         case    OM_SET:
  945.         case    OM_UPDATE:
  946.             rc = PaletteClassSet( cl, obj, ( struct opUpdate * )msg );
  947.             break;
  948.  
  949.         case    GM_RENDER:
  950.             rc = PaletteClassRender( cl, obj, ( struct gpRender * )msg );
  951.             break;
  952.  
  953.         case    GM_GOACTIVE:
  954.             rc = PaletteClassGoActive( cl, obj, ( struct gpInput * )msg );
  955.             break;
  956.  
  957.         case    GM_HANDLEINPUT:
  958.             rc = PaletteClassHandleInput( cl, obj, ( struct gpInput * )msg );
  959.             break;
  960.  
  961.         case    GM_GOINACTIVE:
  962.             rc = PaletteClassGoInactive( cl, obj, ( struct gpGoInactive * )msg );
  963.             break;
  964.  
  965.         case    GRM_DIMENSIONS:
  966.             rc = PaletteClassDimensions( cl, obj, ( struct grmDimensions * )msg );
  967.             break;
  968.  
  969.         case    WM_KEYACTIVE:
  970.             rc = PaletteClassKeyActive( cl, obj, ( struct wmKeyInput * )msg );
  971.             break;
  972.  
  973.         default:
  974.             rc = DoSuperMethodA( cl, obj, msg );
  975.             break;
  976.     }
  977.     return( rc );
  978. }
  979.  
  980. /*
  981. **    Initialize the class.
  982. **/
  983. Class *InitPaletteClass( void )
  984. {
  985.     Class            *super, *cl = NULL;
  986.  
  987.     /*
  988.     **    Obtain the BaseClass pointer which
  989.     **    will be our superclass.
  990.     **/
  991.     if ( super = BGUI_GetClassPtr( BGUI_BASE_GADGET )) {
  992.         /*
  993.         **    Create the class.
  994.         **/
  995.         if ( cl = MakeClass( NULL, NULL, super, sizeof( PD ), 0L ))
  996.             /*
  997.             **    Setup dispatcher.
  998.             **/
  999.             cl->cl_Dispatcher.h_Entry = ( HOOKFUNC )PaletteClassDispatch;
  1000.     }
  1001.     return( cl );
  1002. }
  1003.  
  1004. /*
  1005. **    Kill the class.
  1006. **/
  1007. BOOL FreePaletteClass( Class *cl )
  1008. {
  1009.     return( FreeClass( cl ));
  1010. }
  1011.